package com.and.video.service;

import com.and.video.dao.repository.UserInfoRepository;
import com.and.video.dao.repository.VideoRepository;
import com.and.video.domain.UserInfo;
import com.and.video.domain.Video;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class ElasticSearchService {

    @Autowired
    private VideoRepository videoRepository;

    @Autowired
    private UserInfoRepository userInfoRepository;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    // 添加用户信息到Elasticsearch
    public void addUserInfo(UserInfo userInfo){
        userInfoRepository.save(userInfo);
    }

    // 添加视频信息到Elasticsearch
    public void addVideo(Video video){
        videoRepository.save(video);
    }

    // 根据关键词搜索内容（支持跨索引搜索和高亮显示）
    public List<Map<String, Object>> getContents(String keyword,
                                                 Integer pageNo,
                                                 Integer pageSize) throws IOException {
        // 定义要搜索的索引名称数组（视频索引和用户信息索引）
        String[] indices = {"videos", "user-infos"};
        // 创建搜索请求对象，指定要搜索的索引
        SearchRequest searchRequest = new SearchRequest(indices);
        // 创建搜索源构建器，用于配置搜索参数
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

        // 设置分页参数：起始位置（从0开始）
        sourceBuilder.from(pageNo - 1);
        // 设置分页参数：每页大小
        sourceBuilder.size(pageSize);

        // 创建多字段匹配查询构建器，在title、nick、description字段中搜索关键词
        MultiMatchQueryBuilder matchQueryBuilder = QueryBuilders.multiMatchQuery(keyword, "title", "nick", "description");
        // 将查询条件设置到搜索源构建器中
        sourceBuilder.query(matchQueryBuilder);
        // 将搜索源构建器设置到搜索请求中
        searchRequest.source(sourceBuilder);
        // 设置搜索超时时间为60秒
        sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        // 配置高亮显示设置
        String[] array = {"title", "nick", "description"};  // 需要高亮显示的字段数组
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        // 遍历需要高亮的字段，逐个添加到高亮构建器中
        for(String key : array){
            highlightBuilder.fields().add(new HighlightBuilder.Field(key));
        }
        // 设置不需要字段匹配高亮（多个字段都高亮）
        highlightBuilder.requireFieldMatch(false);
        // 设置高亮前缀（红色样式）
        highlightBuilder.preTags("<span style=\"color:red\">");
        // 设置高亮后缀
        highlightBuilder.postTags("</span>");
        // 将高亮配置设置到搜索源构建器中
        sourceBuilder.highlighter(highlightBuilder);

        // 执行搜索请求，获取搜索响应结果
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        // 创建结果列表，用于存储处理后的搜索结果
        List<Map<String, Object>> arrayList = new ArrayList<>();

        // 遍历搜索命中的结果
        for(SearchHit hit : searchResponse.getHits()){
            // 获取高亮字段信息
            Map<String, HighlightField> highLightBuilderFields = hit.getHighlightFields();
            // 获取原始源数据（Map形式）
            Map<String, Object> sourceMap = hit.getSourceAsMap();

            // 遍历需要高亮的字段数组
            for(String key : array){
                // 获取当前字段的高亮信息
                HighlightField field = highLightBuilderFields.get(key);
                if(field != null){
                    // 获取高亮片段数组
                    Text[] fragments = field.fragments();
                    // 将高亮片段数组转换为字符串
                    String str = Arrays.toString(fragments);
                    // 去除字符串两端的方括号
                    str = str.substring(1, str.length()-1);
                    // 用高亮后的内容替换原始内容
                    sourceMap.put(key, str);
                }
            }
            // 将处理后的结果添加到结果列表中
            arrayList.add(sourceMap);
        }
        // 返回搜索结果列表
        return arrayList;
    }

    // 根据关键词搜索视频（使用JPA方式）
    public Video getVideos(String keyword){
        return videoRepository.findByTitleLike(keyword);  // 使用JPA的模糊查询方法
    }

    // 删除所有视频数据
    public void deleteAllVideos(){
        videoRepository.deleteAll();  // 使用JPA删除所有视频数据
    }
}